#include <iostream>
#include "Task.hpp"
#include <string>
#include <unistd.h>
#include <vector>
#include <cassert>
#include <ctime>
#include <sys/wait.h>
#include <sys/stat.h>

const int processnum = 5;
std::vector<task_t> tasks;

//先描述
class channel 
{
public:
    channel(int cmdfd, pid_t slaverid, const std::string processname)
        :_cmdfd(cmdfd)
        ,_slaverid(slaverid)
        ,_processname(processname)
    {}
public:
    int _cmdfd;      //发送任务码的文件描述符
    pid_t _slaverid; //子进程的PID
    std::string _processname;//子进程的名字
};

// void slaver(int rfd)
// {
//     while(1)
//     {
//         std::cout << "I am child: pid: " << getpid() << "I am read pipefd: " << rfd << std::endl;
//         sleep(100000);
//     }
// }
void slaver()
{
    //0号文件拿任务即可
    while(1)
    {
        // std::cout << "I am child: pid: " << getpid() << "I am read pipefd: " << 0 << std::endl;
        // sleep(100000);
        int cmdcode = 0;
        int n = read(0, &cmdcode, sizeof(int)); //如果父进程不给子进程发送数据，那么阻塞等待
        if(n == sizeof(int))
        {
            //执行cmdcode对应的任务列表
            std::cout << "I am chid, pid: " << getpid() << ",I access a cmdcode : " << cmdcode << std::endl;
            if(cmdcode >= 0 || cmdcode < tasks.size()) tasks[cmdcode]();
        }
        if(n == 0) break;
    }
}
//输入: const &
//输出： *
//输入输出：&
void InitProcessPool(std::vector<channel>* channels)
{   
    std::vector<int> oldfds;
    for(int i = 0; i < processnum; i++)
    {
        int pipefd[2]; //临时空间
        int n = pipe(pipefd);
        assert(n == 0);
        (void)n;

        pid_t id = fork();
        if(id == 0) //child
        {  
            std::cout << "child: " << getpid() << " close history fd: ";
            for(auto fd : oldfds) 
            {
                close(fd);
                std::cout << fd << " ";
            }
            std::cout << std::endl;
            close(pipefd[1]);
            dup2(pipefd[0], 0);
            close(pipefd[0]);
            slaver();
            std::cout << "process exit :" << getpid() << std::endl;
            //slaver(pipefd[0]);
            exit(0);
        }
        //father
        close(pipefd[0]);

        //添加channnel字段
        std::string name = "process-" + std::to_string(i);
        channels->push_back(channel(pipefd[1], id, name));
        oldfds.push_back(pipefd[1]);
    } 
}

void Debug(const std::vector<channel>& channels)
{
    for(auto& e : channels)
    {
        std::cout << e._cmdfd << ", " << e._slaverid << ", " << e._processname << std::endl;
    }
}
void Menu()
{
    std::cout << "**********************************************" << std::endl;
    std::cout << "*********** 1. 原神启动！       ***************" << std::endl;
    std::cout << "*********** 2. 王者荣耀启动！   ***************" << std::endl;
    std::cout << "*********** 3. 三国杀启动！     ***************" << std::endl;
    std::cout << "*********** 4. 金铲铲启动！     ***************" << std::endl;
    std::cout << "*********** 0. 退出            ***************" << std::endl;
    std::cout << "**********************************************" << std::endl;
    std::cout << "Please Enter@" << std::endl;
}
void ctrlSlaver(const std::vector<channel>& channels)
{
    int which = 0;
    // for(int i = 0; i < tasks.size(); i++)
    // {
    //     //1.选择任务
    //     int cmdcode = i;
    //     //2.选择进程
    //     //需要负载均衡：轮询或者随机数法
    //     //int processpos = rand() % channels.size();
    //     std::cout << "father say: cmdcode:" << cmdcode << " , already sentto " << channels[which]._slaverid << std::endl;
    //     //3.发送任务
    //     write(channels[which]._cmdfd, &cmdcode, sizeof(int));
    //     sleep(1);
    //     which++;
    //     which = which % channels.size();
    // }
    while(true)
    {
        int cmdcode = 0;
        Menu();

        std::cin >> cmdcode;
        if(cmdcode <= 0 || cmdcode >= 5) break;
        cmdcode--;
        //1.选择任务
        //2.选择进程
        std::cout << "father say: cmdcode:" << cmdcode << " , already sentto " << channels[which]._slaverid << std::endl;
        //3.发送任务
        write(channels[which]._cmdfd, &cmdcode, sizeof(int));
        sleep(1); 
        which++; 
        which = which % channels.size();
    }
}
// void QuitProcess(const std::vector<channel>& channels)
// {
//     for(const auto& c : channels)
//     {
//         close(c._cmdfd);
//         std::cout << "关闭了一个写端的文件" << std::endl;
//         //sleep(1);
//     }
//     //sleep(5);
//     for(const auto& c : channels)
//     {
//         waitpid(c._slaverid,nullptr,0);
//         //sleep(1);
//     }
//     //sleep(5);
// }
void QuitProcess(const std::vector<channel>& channels)
{
    for(const auto& c : channels)
    {
        close(c._cmdfd);
        waitpid(c._slaverid,nullptr,0);
    }
}
// void QuitProcess(const std::vector<channel>& channels)
// {
//     for(int i = channels.size() - 1; i >= 0; i--)
//     {
//         close(channels[i]._cmdfd);
//         sleep(1);
//         waitpid(channels[i]._slaverid,nullptr,0);
//         sleep(1);
//     }
// }
int main()
{
    LoadTask(&tasks);
    srand(time(nullptr)^getpid()^1023); //种一个随机数种子
    //在组织
    std::vector<channel> channels;    
    //1.初始化
    InitProcessPool(&channels);
    //test
    Debug(channels);

    //2.开始控制子进程
    ctrlSlaver(channels);

    //3.清理收尾    
    QuitProcess(channels);
    //sleep(5);
    return 0;
}